#include <functional> // For std::function
#include <QtCore/QSysInfo>
#include <QtCore/QString>
#include <QtCore/QProcess>
#include <QtCore/QUrl>
#include <QtCore/QTimer>
#include <QtCore/QStringListModel>
#include <QtCore/QRandomGenerator>
#include <QtGui/QStandardItemModel>
#include <QtGui/QStandardItem>
#include <QtGui/QDesktopServices>
#include <QtGui/QCursor>

#include <QtConcurrent/QtConcurrent>
#include <QtCore/QFutureWatcher>
#include <QtCore/QMetaObject>
#include "includes.txt"

const QString Title( "QWidgets Start MessageBox" );

//只添加UI的组件，不涉及到辅助的组件部分。
void addLayOutWidgets(QLayout * layout){
	//1:QPlainTextEdit,富文本输入控件
	{
		QPlainTextEdit *plainTextEdit = new QPlainTextEdit();
		plainTextEdit->setPlainText("Initial text here.");
		//设置外观和行为
		QFont font;
		font.setFamily("Courier");
		font.setStyleHint(QFont::Monospace);
		font.setFixedPitch(true);
		font.setPointSize(10);

		plainTextEdit->setFont(font);
		//只读模式：
		//plainTextEdit->setReadOnly(true);  // 用户不能编辑文本
		//开启或关闭换行模式,默认支持Wrap模式，
		//plainTextEdit->setWordWrapMode(QTextOption::NoWrap);//Enum 四种值
		
		//添加信号
		QObject::connect( plainTextEdit, &QPlainTextEdit::textChanged,[=](){
			qDebug() << plainTextEdit->toPlainText();
		});
		layout->addWidget(plainTextEdit);
	}
	//2：QProgressBar 进度条，可以嵌入的UI控件，正常使用是，其他Event通知它变动
	{
		QProgressBar *progressBar = new QProgressBar();
		progressBar->setMinimum(0); // 默认为 0
		progressBar->setMaximum(100); // 默认为 100
		//垂直模式，默认是水平的
		//progressBar->setOrientation(Qt::Vertical);
		//样式和外观
		// 使用样式表改变外观
		progressBar->setStyleSheet("QProgressBar {border: 2px solid grey; border-radius: 5px;}"
                           "QProgressBar::chunk {background-color: #05B8CC;}");
                           
        progressBar->setValue(0);//要将 这个放在Timer的Timer里面或者Thread中，这样只会显示一段。
        
        //这里用QTimer 触发
        QTimer * timer = new QTimer(progressBar);//绑定在progressBar上
        QObject::connect( timer, &QTimer::timeout,[=](){
			quint32 value = QRandomGenerator::global()->generate() % 100 ;
			progressBar->setValue(value);
		});
		timer->start(50);//每50ms 触发一次
		
        layout->addWidget(progressBar);
	}
	//3：QScrollBar，滚动条控件，当然是和其他控件一起使用
	{
		//QScrollBar *scrollBar = new QScrollBar();
		//方向
		QScrollBar *scrollBar = new QScrollBar(Qt::Horizontal);
		scrollBar->setMinimum(0); // 设置最小值
		scrollBar->setMaximum(100); // 设置最大值
		scrollBar->setValue(50); // 设置当前滑块位置
		
		scrollBar->setPageStep(10);
		scrollBar->setSingleStep(1);
		
		//添加信号
		QObject::connect( scrollBar, &QScrollBar::valueChanged,[=](int value){
			qDebug("Scroll bar moved to %d", value);
		});
		
		layout->addWidget(scrollBar);
		
	}
	//4:QSlider,滑条，带数字
	{
		QSlider *slider = new QSlider(Qt::Horizontal); // 创建一个水平滑块
		//QSlider *slider = new QSlider(Qt::Vertical); // 创建一个垂直滑块
		
		//设置滑块的范围和初始值
		slider->setMinimum(0);      // 设置最小值
		slider->setMaximum(100);    // 设置最大值
		slider->setValue(50);       // 设置当前值
		
		//信号和槽
		QObject::connect(slider, &QSlider::valueChanged, [=](int value){
		   // 这里处理滑块值改变的事件，比如更新标签显示当前值
		   qDebug("QSlider moved to %d", value);
		});
		//自定义外观
		slider->setTickPosition(QSlider::TicksBelow); // 将刻度线放置在滑块下方
		slider->setTickInterval(10);                  // 设置刻度间隔
		
		layout->addWidget(slider);
	}
	//5：QSpinBox，微调或者输入的数字的控件
	{
		QSpinBox *spinBox = new QSpinBox;
		
		spinBox->setMinimum(0);  // 设置最小值
		spinBox->setMaximum(100); // 设置最大值
		spinBox->setValue(50); // 设置当前值
		
		//信号和槽
		QObject::connect(spinBox, &QSpinBox::valueChanged, [=](int value){
		   // 这里处理滑块值改变的事件，比如更新标签显示当前值
		   qDebug("QSpinBox moved to %d", value);
		});
		
		//自定义外观 细节
		spinBox->setSingleStep(1); // 设置步长
		layout->addWidget(spinBox);
	}
	//6：QStatusBar
	{
		QStatusBar *statusBar = new QStatusBar;
		statusBar->showMessage("This is a status message.", 2000); // 显示2秒
		
		//添加永久的小组件
		QLCDNumber *lcdNumber = new QLCDNumber();
		lcdNumber->setDigitCount(5);
		lcdNumber->display(5555); // 显示整数
		//lcdNumber->display(12.345); // 显示浮点数
		lcdNumber->setSegmentStyle(QLCDNumber::Flat);//样式
		statusBar->addPermanentWidget(lcdNumber);
		
		//也可以添加临时小部件，这会替换掉任何临时消息，并在下一次调用 showMessage() 时被移除。
		//QWidget *temporaryWidget = new QWidget();
		//statusBar->addWidget(temporaryWidget);
		
		layout->addWidget(statusBar);
		
	}
	//7:QTabBar
	{
		QTabBar *tabBar = new QTabBar;
		//add tab
		tabBar->addTab("Tab 1");
		tabBar->addTab(QIcon("dog.png"), "Tab 2");
		//设置当前
		tabBar->setCurrentIndex(0);
		//改变外观
		tabBar->setIconSize(QSize(16, 16));
		//改变某一个
		tabBar->setTabText(0, "Fist Tab Text");
		tabBar->setTabText(1, "Second Tab Text");
		tabBar->setTabTextColor(0, QColor(Qt::red));
		tabBar->setTabTextColor(1, QColor(Qt::yellow));
		
		//样式表
		tabBar->setStyleSheet("QTabBar::tab { background: lightgray; }"
                      "QTabBar::tab:selected { background: gray; }");
                      
		QObject::connect(tabBar, &QTabBar::currentChanged, [=](int index){
			qDebug("QTabBar Change Tab to %d", index);
		});
		layout->addWidget(tabBar);
	}
	//8：QTableView
	{
		QTableView* tableView = new QTableView;
		QStandardItemModel* model = new QStandardItemModel(5, 3); // 假设我们有5行3列

		// 设置首行样式
		for (int column = 0; column < 3; ++column) {
			QStandardItem *firstRowItem = new QStandardItem(QString("Header %1").arg(column));
			firstRowItem->setBackground(QBrush(Qt::gray)); // 首行背景色
			firstRowItem->setForeground(QBrush(Qt::white)); // 首行文字颜色
			QFont font = firstRowItem->font();
			font.setBold(true); // 首行文字加粗
			firstRowItem->setFont(font);
			model->setItem(0, column, firstRowItem);
		}

		// 为每行设置颜色
		for (int row = 1; row < 5; ++row) {
			for (int column = 0; column < 3; ++column) {
				QStandardItem *item = new QStandardItem(QString("Item %1").arg(row * column));
				// 根据行号设置不同的颜色
				if (row % 2 == 1) {
					item->setBackground(QBrush(Qt::lightGray));
				} else {
					item->setBackground(QBrush(Qt::darkGray));
				}
				model->setItem(row, column, item);
			}
		}
		//链接信号与槽,没有对应的信号。
		
		//要定制，一种是自定义委托（不用），现在试用QSS来改变选中的样式
		tableView->setStyleSheet("QTableView::item:selected { background-color: #567dbc; color: white; }");
		tableView->setModel( model );
		layout->addWidget(tableView);
	}
	//9:QTableWidget
	{
		QTableWidget *tableWidget = new QTableWidget;
		const int RowCount = 10;
		const int ColCount = 5;
		tableWidget->setRowCount(RowCount); // 设置为10行
		tableWidget->setColumnCount(ColCount); // 设置为5列
		//添加表头
		QStringList headers;
		headers << "Header 1" << "Header 2" << "Header 3" << "Header 4" << "Header 5";
		tableWidget->setHorizontalHeaderLabels(headers);
		tableWidget->verticalHeader()->setVisible(false); // 如果不想显示行号
		// 为每行设置颜色,插入Item
		for (int row = 0; row < RowCount; ++row) {
			for (int column = 0; column < ColCount; ++column) {
				QTableWidgetItem *item = new QTableWidgetItem(QString("Item %1").arg(row * ColCount + column));
				// 根据行号设置不同的颜色
				if (row % 2 == 1) {
					item->setBackground(QBrush(Qt::lightGray));
				} else {
					item->setBackground(QBrush(Qt::darkGray));
				}
				tableWidget->setItem(row, column, item);
			}
		}
		//调整大小，开放了放在最下面很容易闪烁，似乎是必然的情况。
		//tableWidget->resizeColumnsToContents(); // 调整列宽以适应内容
		//tableWidget->resizeRowsToContents(); // 调整行高以适应内容
		//处理选择
		tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
		tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
		//链接信号与槽
		QObject::connect(tableWidget, &QTableWidget::cellClicked, [=](int row, int column){
			qDebug("QTableWidget Click Cell (%d,%d) ", row,column);
		});
		//一次选了一行，与上面的选择处理有关系。
		QString styleSheet =
		"QTableWidget::item:selected:active { background-color: #568af2; color: white; }"
		"QTableWidget::item:selected:!active { background-color: #cccccc; color: black; }";

		tableWidget->setStyleSheet(styleSheet);
		layout->addWidget(tableWidget);
	}
	//10 QTextEdit
	{
		QTextEdit *textEdit = new QTextEdit;
		// 设置为普通文本
		//textEdit->setPlainText("这里是一些文本");

		// 或者设置为 HTML 内容
		textEdit->setHtml("<b>这是加粗的文本</b>");
		
		textEdit->setReadOnly(false); // 设置为可编辑，如果你想要一个只读的文本浏览器，请将其设置为 true
		textEdit->setFont(QFont("Arial", 12)); // 设置字体
		
		//连接信号和槽
		QObject::connect(textEdit, &QTextEdit::textChanged, [=](){
			qDebug()<<"TextEdit Content :"<<textEdit->toPlainText();
		}
		);
		layout->addWidget(textEdit);
	}
	//11 QToolBar
	{
		QToolBar *toolbar = new QToolBar("My Toolbar", nullptr);
		QAction *action = new QAction(QIcon("dog.png"), "Action Label", toolbar);
		QObject::connect(action, &QAction::triggered, [=](){
			qDebug()<<"Action Label : Triggered";
		});
		toolbar->addAction(action); // 将动作添加到工具栏
		//添加小组件
		QPushButton *button = new QPushButton("Button", toolbar);
		toolbar->addWidget(button); // 将按钮添加到工具栏
		layout->addWidget(toolbar);
	}
	//12 QToolButton
	{
		QToolButton *toolButton = new QToolButton;
		toolButton->setIcon(QIcon("dog.png"));
		toolButton->setText("Button Label");
		
		toolButton->setToolTip("This is a tool button");
		toolButton->setCheckable(true); // 让按钮具备切换功能
		
		QObject::connect(toolButton, &QToolButton::clicked, [=](){
			qDebug()<<"QToolButton clicked ";
		});
		
		//设置按钮弹出模式，与响应clicked信号不同 NOTE：：
		QMenu *menu = new QMenu(toolButton);
		QAction *action1 = menu->addAction("Option 1");
		// ...添加更多的动作...
		toolButton->setMenu(menu);
		toolButton->setPopupMode(QToolButton::InstantPopup);
		
		layout->addWidget(toolButton);
	}
	//13 QTreeView 
	{
		// 创建一个标准项模型
		QStandardItemModel* model = new QStandardItemModel();
		QStandardItem* parentItem = model->invisibleRootItem();

		// 设置列头
		model->setHorizontalHeaderLabels({ "标题", "描述" });

		// 填充数据
		for (int i = 0; i < 3; ++i) {
			// 父项
			QStandardItem* parent = new QStandardItem(QString("项目 %1").arg(i));
			QStandardItem* desc = new QStandardItem(QString("描述 %1").arg(i));
			parentItem->appendRow({ parent, desc });

			// 子项
			for (int j = 0; j < 5; ++j) {
				QStandardItem* child = new QStandardItem(QString("子项目 %1-%2").arg(i).arg(j));
				QStandardItem* childDesc = new QStandardItem(QString("子描述 %1-%2").arg(i).arg(j));
				parent->appendRow({ child, childDesc });
			}
		}
		
		QTreeView* treeView = new QTreeView;
		treeView->setModel(model);
		//用QSS 定制外观
		QString styleSheet = 
		"QTreeView { border: 1px solid gray;background-color: #f0f0f0; margin: 5px;}"
		"QTreeView::item { border: 1px solid #d9d9d9; padding: 3px; margin: 2px;}"
		"QTreeView::item:hover { background-color: #ebebeb; }"
		"QTreeView::item:selected { background-color: #5895f0;}"
		;
		
		treeView->setStyleSheet( styleSheet );
		layout->addWidget(treeView);
	}
	//14 QTreeWidget 是Qt提供的一个方便的树行结构控件，可以让你在用户界面和编辑项的分层数据。跟View比 明确了Head
	{
		QTreeWidget *treeWidget = new QTreeWidget;
		//设置列头
		treeWidget->setHeaderLabels(QStringList()<<"项目 1"<<"项目 2"<<"项目 3");
		//添加项目 QTreeWidgetItem
		// 添加根项目
		QTreeWidgetItem *rootItem = new QTreeWidgetItem(treeWidget);
		rootItem->setText(0, "Root Item");

		// 添加子项目
		QTreeWidgetItem *childItem = new QTreeWidgetItem(rootItem);
		childItem->setText(0, "Child Item");
		childItem->setText(1, "Value 1");
		
		//展开和折叠：
		rootItem->setExpanded(true); // 展开根项目
		childItem->setExpanded(false); // 折叠子项目
		
		// 设置选择模式
		treeWidget->setSelectionMode(QAbstractItemView::SingleSelection); // 或 MultiSelection, ExtendedSelection 等
		QObject::connect(treeWidget, &QTreeWidget::itemClicked, [=](QTreeWidgetItem *item, int column){
			qDebug() << "Item clicked:" << item->text(column);
		});
		//排序
		treeWidget->setSortingEnabled(true); // 启用排序
		treeWidget->sortByColumn(0, Qt::AscendingOrder); // 根据第一列以升序排序
		
		treeWidget->setStyleSheet( "QTreeWidget { border: 1px solid gray;background-color: #f0f0f0; margin: 5px;}" );
		
		layout->addWidget(treeWidget);
	}
}

//无法独立使用GUI控件，或者主要目标是辅助类型的，或者顶级窗口，比如带Dialog的类型
void addLayoutCommonSettings(QLayout * layout, QWidget* window,QApplication * app){
#if 0 //有很明显的问题，整个布局都乱了。应该用弹窗的方式来显示吧 ，直接丢到window里面 就乱了
	//0 QWizard
	{
		QWizard* wizard = new QWizard;
		wizard->setWindowTitle("Simple Wizard Example");
		
		QWizardPage * introPage = new QWizardPage();
		
		introPage->setTitle("Introduction");
        introPage->setSubTitle("This wizard will help you register your copy of Super Product Two.");
        #if 0
        {
			QLabel *label = new QLabel("This wizard will guide you through the registration process.");
			label->setWordWrap(true);
			
			QVBoxLayout *layout1 = new QVBoxLayout;
			layout1->addWidget(label);
			introPage->setLayout(layout1);
        }
        #endif
        wizard->addPage( introPage );
        
        QWizardPage * registrationPage = new QWizardPage();       
        registrationPage->setTitle("Registration");
        registrationPage->setSubTitle("Please fill both fields.");
        #if 0
        {
			QPlainTextEdit *plainTextEdit = new QPlainTextEdit();
			plainTextEdit->setPlainText("Initial text here.");
			
			QVBoxLayout *layout1 = new QVBoxLayout;
			layout1->addWidget(plainTextEdit);
			registrationPage->setLayout(layout1);
        }
        #endif
        wizard->addPage( registrationPage );
        
        layout->addWidget(wizard);
	}
	#endif
	//1：QMessageBox，传统的Modal Dialog的情况
	{
		//固定的信息
		QPushButton* button = new QPushButton("QMessageBox Demo"); // 创建一个按钮，并设置显示文本
		QObject::connect(button, &QPushButton::clicked,  []()
		{
			QMessageBox msgBox;
			msgBox.setWindowTitle("Custom Dialog");
			msgBox.setIcon(QMessageBox::Question);
			msgBox.setText("This is a custom message box.");
			msgBox.setInformativeText("Do you want to save your changes?");
			msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
			msgBox.setDefaultButton(QMessageBox::Save);

			int ret = msgBox.exec(); // 显示消息框并等待用户响应
			qDebug() << "QMessageBox exec result."<< ret;
		}); 
		layout->addWidget(button);
	}
	//2：QProgressDialog，这里结合QtConcurrent的机制来更新进度条
	{
		QPushButton* button = new QPushButton("QProgressDialog Demo");

		QObject::connect(button, &QPushButton::clicked, [=]() {
			auto progressDialog = new QProgressDialog("Copying files...", "Cancel", 0, 100);
			progressDialog->setWindowModality(Qt::WindowModal);
			progressDialog->setAttribute(Qt::WA_DeleteOnClose);

			// 使用QFuture和QPromise更新进度
			QFuture<void> future = QtConcurrent::run([progressDialog](QPromise<void>& promise) {
				promise.setProgressRange(0, 100);
				for (int i = 0; i <= 100; ++i) {
					// 在这里执行长时间运行的任务

					// 更新进度
					promise.setProgressValue(i);

					// 处理取消请求
					if (promise.isCanceled()) {
						break;
					}

					// 模拟耗时操作
					QThread::msleep(100);
				}				
			});

			// 创建QFutureWatcher来监视任务
			QFutureWatcher<void>* futureWatcher = new QFutureWatcher<void>();
			futureWatcher->setFuture(future);

			QObject::connect(progressDialog, &QProgressDialog::canceled,
							 futureWatcher, &QFutureWatcher<void>::cancel);

			QObject::connect(futureWatcher, &QFutureWatcher<void>::progressValueChanged,
							 progressDialog, &QProgressDialog::setValue);

			QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() {
				progressDialog->close();
				futureWatcher->deleteLater();
				//TODO：：始终输出Task was canceled，折腾半天没找到。等下一轮吧
				if (future.isCanceled()) {
					qDebug() << "Task was canceled";
				} else if (future.isFinished()) {
					qDebug() << "Task completed successfully";
				}
			});
		});

		layout->addWidget(button);

	}
	//3：QSizeGrip，给整个Window加个窗口大小调整的功能，它自身是隐身的，注意
	{
		QSizeGrip *sizeGrip = new QSizeGrip(window);

		// 如果需要，可以设置 sizeGrip 的位置
		// sizeGrip->move(window->width() - sizeGrip->width(), window->height() - sizeGrip->height());
		layout->addWidget(sizeGrip);
		sizeGrip->setStyleSheet(
			"QSizeGrip {"
			"   width: 20px;"
			"   height: 20px;"
			"   image: url(:/images/sizegrip.png);"
			"}"
		);
	}
	//4：QSizePolicy，size的策略，可以根据QSizeGrip的结果来结合的看 就知道为什么了。
	{
		// 创建两个按钮
		QPushButton *button1 = new QPushButton("Test Fixed");
		// 创建并设置第一个按钮的大小策略为固定大小
		QSizePolicy policy1(QSizePolicy::Fixed, QSizePolicy::Fixed);//不变的情况
		button1->setSizePolicy( policy1 );
		// 创建两个按钮
		QPushButton *button2 = new QPushButton("Test Expanding");
		// 创建并设置第一个按钮的大小策略为固定大小
		QSizePolicy policy2(QSizePolicy::Expanding, QSizePolicy::Fixed);//扩展的情况
		button2->setSizePolicy( policy2 );
		
		layout->addWidget(button1);
		layout->addWidget(button2);
	}
	//5：QStyleFactory的用法，使用ComboBox来展示所有的类型，然后选择之后 就设置到这个ComboBox上面
	{
		QComboBox * comboBox = new QComboBox();
		//add items
		comboBox->addItems(QStyleFactory::keys());
		
		auto* label = new QLabel("Select an Style...");
		layout->addWidget(label);
		
		QObject::connect(comboBox, &QComboBox::currentTextChanged,
        [=](const QString &text){ 
			comboBox->setStyle(QStyleFactory::create(text)); 
			//QApplication::setStyle(style);
			label->setText(QString("Selected Style: %1").arg(text));
			});
        layout->addWidget(comboBox);
	}
	
}
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建一个窗口
    QWidget window;
    window.setWindowTitle(Title);
	window.resize(400,100);
    // 使用垂直布局
    QVBoxLayout *layout = new QVBoxLayout(&window);
    
    //这里是主要的过程，挨个添加在里面。
    addLayoutCommonSettings( layout, &window, &app);
	addLayOutWidgets( layout );
	
	//固定的信息
	QPushButton* button = new QPushButton(QString("click=>quit! %1").arg( qVersion() ) ); // 创建一个按钮，并设置显示文本
	//显然不适合这个按钮，它点就退出了。
	button->setWhatsThis("当你点击这个按钮，程序就退出了。");//可以通过在菜单或工具栏中添加一个特定的 “What’s This?” 按钮来实现。用户点击该按钮后，光标会变成一个问号，此时可以点击任何部件查看帮助。 
    QObject::connect(button, &QPushButton::clicked, [&](){
		QWhatsThis::enterWhatsThisMode();
		app.quit();
    }); // 连接按钮的clicked信号到QApplication的quit槽函数
	layout->addWidget(button);
    // 设置布局并显示窗口
    window.setLayout(layout);
    window.show();

    // 运行应用程序事件循环
    return app.exec();
}